package com.anji.plus.gaea.security.security;


import com.anji.plus.gaea.security.GaeaSecurityProperties;
import com.anji.plus.gaea.security.event.EventEnum;
import com.anji.plus.gaea.security.event.UserApplicationEvent;
import com.anji.plus.gaea.security.security.extension.UserDetailsServiceHelper;
import com.anji.plus.gaea.utils.ApplicationContextUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

/**
 * 自定义security的UserDetailsService,从数据库获取用户信息
 *
 * @author lr
 * @since 2021-01-25
 */
public class GaeaUserDetailsService implements UserDetailsService {

    @Autowired
    private UserDetailsServiceHelper userDetailsServiceHelper;

    @Autowired
    private GaeaSecurityProperties gaeaSecurityProperties;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //根据用户名查询用户
        UserDetails userDetails;
        try {
            userDetails = userDetailsServiceHelper.findByUsername(username);
        } catch (Exception e) {
            throw new UsernameNotFoundException(username);
        }

        //当用户不存在时
        if (userDetails == null) {
            throw new UsernameNotFoundException(username);
        }

        boolean credentialsNonExpired = userDetails.isCredentialsNonExpired();

        //当密码没有过期时，判断密码上次更新时间
        if (credentialsNonExpired) {
            //判断密码是否过期
            LocalDateTime passwordUpdateTime = userDetailsServiceHelper.getPasswordUpdateTime(username);
            if (passwordUpdateTime != null) {
                //相差的秒数
                long seconds = passwordUpdateTime.until(LocalDateTime.now(), ChronoUnit.SECONDS);
                //过期时长
                int expireSeconds = gaeaSecurityProperties.getCredentialsExpiredLength() * 24 * 3600;
                //过期标识

                //如果相差的秒数超过过期时长，则密码过期
                if (seconds >= expireSeconds) {
                    credentialsNonExpired = false;
                    //发布密码过期事件
                    ApplicationContextUtils.publishEvent(new UserApplicationEvent(username, EventEnum.CERDENTIALS_EXPIRE));
                }
            }
        }

        return User.builder().username(username)
                .password(userDetails.getPassword())
                //设置默认值，security会校验
                .authorities(new String[0])
                .disabled(!userDetails.isEnabled())
                .accountExpired(!userDetails.isAccountNonExpired())
                .accountLocked(!userDetails.isAccountNonLocked())
                .credentialsExpired(!credentialsNonExpired).build();
    }
}
